Period picker
Allow users to select a range of dates quickly and intuitively.
#Examples
Default: Button shows selected range with presets available. Always has a default presets with the most commonly used date range.
Period picker consists of two main elements:
- Button (with clock icon) using two lines:
- Line 1: Active preset or custom date range.
- Line 2: Start and end dates of selected range
- Popover (triggered by button click) with:
- Preset tabs (e.g., "Last 7 Days," "Last Month")
- Interactive calendar view for custom range selection
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return <PeriodPicker aria-label="Select period" value={period} onChange={setPeriod} />;#Usage with hidden presets
Used when preset data is unavailable, focusing on custom selection.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return (
<PeriodPicker
aria-label="Select period"
value={period}
onChange={setPeriod}
hiddenPresets={[
PeriodType.LastSevenDays,
PeriodType.LastFourteenDays,
PeriodType.LastThirtyDays,
PeriodType.Last365Days,
]}
/>
);#Usage with condensed variant
Button (with clock icon) displaying selected range in one line.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return <PeriodPicker aria-label="Select period" value={period} onChange={setPeriod} condensed />;#Usage with time zone conversion
When the dates are provided in UTC format (e.g. when dates from the server are not localized) make sure to convert it from UTC to local when passed to the value prop and from local to UTC when updating the period state from within the onChange callback.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
function localToUtc(date: Date): Date {
return new Date(
Date.UTC(
date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds()
)
);
}
function utcToLocal(date: Date): Date {
return new Date(
date.getUTCFullYear(),
date.getUTCMonth(),
date.getUTCDate(),
date.getUTCHours(),
date.getUTCMinutes(),
date.getUTCSeconds()
);
}
return (
<PeriodPicker
aria-label="Select period"
value={
period
? {
start: utcToLocal(period.start),
end: utcToLocal(period.end),
type: period.type,
}
: null
}
onChange={(period) => {
setPeriod(
period
? {
start: localToUtc(period.start),
end: localToUtc(period.end),
type: period.type,
}
: null
);
}}
/>
);#Usage with UTC offset
When a UTC offset is provided, all preset calculations (such as "Last 5 minutes", "Yesterday", etc.) are based on the current time adjusted by that offset. This means "now" reflects the time at the specified UTC offset, not the system or browser time.
const utcOffset = -10 * 60; // Example UTC offset in minutes (-10 hours)
const now = new Date();
now.setMinutes(now.getMinutes() + utcOffset); // Adjust current time by UTC offset
const start = new Date(now.getTime() - 5 * 60 * 1000); // 5 minutes ago
const end = new Date(now);
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start,
end,
type: PeriodType.Now,
});
return (
<Content flexDirection="row" padding="none" gap="large">
<PeriodPicker
aria-label="Select period"
value={period}
onChange={setPeriod}
options={{ utcOffset }}
/>
{period && (
<div>
<div>
<InlineText>{`Start: ${period.start.toISOString()}`}</InlineText>
</div>
<div>
<InlineText>{`End: ${period.end.toISOString()}`}</InlineText>
</div>
</div>
)}
</Content>
);#Usage with includeToday option
When includeToday: false is set, the "This Month", "This Quarter", and "This Year" presets will end at yesterday instead of today. By default, includeToday is true.
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return (
<Content flexDirection="row" padding="none" gap="large">
<PeriodPicker
aria-label="Select period with includeToday option"
value={period}
onChange={setPeriod}
options={{ includeToday: false }}
/>
{period && (
<div>
<div>
<InlineText>{`Start: ${period.start.toISOString()}`}</InlineText>
</div>
<div>
<InlineText>{`End: ${period.end.toISOString()}`}</InlineText>
</div>
</div>
)}
</Content>
);#Usage with week start
When a week start is provided, the calendar view will start the week on the specified day. This is useful when the user's locale or system week start day is different from the default (Sunday).
const [period, setPeriod] = React.useState<PeriodPickerValue | null>({
start: new Date(2023, 4, 1),
end: new Date(2023, 4, 31),
type: PeriodType.Custom,
});
return (
<Content flexDirection="row" padding="none" gap="large">
<PeriodPicker
aria-label="Select period with week starting Monday"
value={period}
onChange={setPeriod}
options={{ weekStart: 1 }} // 0 = Sunday, 1 = Monday, 2 = Tuesday, etc.
/>
{period && (
<div>
<div>
<InlineText>{`Start: ${period.start.toISOString()}`}</InlineText>
</div>
<div>
<InlineText>{`End: ${period.end.toISOString()}`}</InlineText>
</div>
</div>
)}
</Content>
);#Properties
| Property | Description | Defined | Value |
|---|---|---|---|
valueRequired | | objectThe value of the component | ||
onChangeRequired | functionCallback that is called when the value changes | ||
optionsOptional | objectOptions for period calculations | ||
minDateOptional | date | ||
maxDateOptional | date | ||
literal-union[] | |||
condensedOptional | boolean | ||
disabledOptional | booleanWhether the component is disabled | ||
aria-labelOptional | stringLabel of the form control | ||
aria-describedbyOptional | stringID of an an element that describes what the form control is for | ||
aria-labelledbyOptional | stringID of an an element that labels this form control | ||
periodButtonVariantOptional | "borderless" | "ctaDefault" | "ctaPrimary" | "ctaSecondary" | "default" | "destructive" | "primary" | "secondary"How should the button look | ||
periodButtonSizeOptional | "large" | "medium" | "small"Controls the size of the button - defaults to medium | ||
periodButtonStyleOptional | objectAdd inline style for the button only if necessary | ||
strategyOptional | "absolute" | "fixed"Position popover using fixed or absolute | ||
data-observe-keyOptional | stringUnique string, used by external script e.g. for event tracking | ||
classNameOptional | stringCustom className that's applied to the outermost element (only intended for special cases) | ||
styleOptional | objectStyle object to apply custom inline styles (only intended for special cases) | ||
tabIndexOptional | numberTab index of the outermost HTML element of the component | ||
onKeyDownOptional | functionCallback for onKeyDown event | ||
onMouseDownOptional | functionCallback for onMouseDown event | ||
onMouseEnterOptional | functionCallback for onMouseEnter event | ||
onMouseLeaveOptional | functionCallback for onMouseLeave event | ||
onFocusOptional | functionCallback for onFocus event | ||
onBlurOptional | functionCallback for onBlur event |
#Guidelines
#Best practices
#Do not use when
#Accessibility
Explore detailed guidelines for this component: Accessibility Specifications